home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
1991
/
02
/
386bsd.feb
next >
Wrap
Text File
|
1990-12-26
|
26KB
|
766 lines
_PORTING UNIX TO THE 386: THREE INITIAL PC UTILITIES_
by William F. Jolitz and Lynne G. Jolitz
[LISTING ONE]
/* Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
* Written by William Jolitz 7/89
* Redistribution and use in source and binary forms are freely permitted
* provided that the above copyright notice and attribution and date of work
* and this paragraph are duplicated in all such forms.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* This program allows the bootstrap load of GCC cross compiled
* 32 bit protected mode absolute programs onto the obtuse architecture
* of PC AT/386, destroying the running DOS in the process.
* Currently works with TURBO C 1.5 & MASM 5.0, relies on farmalloc().
*/
#pragma inline
#include <io.h>
#include <fcntl.h>
#include <alloc.h>
#include <dos.h>
#include <sys\stat.h>
#include "exec.h"
#define PGSIZE 4096
#define CLOFSET (PGSIZE - 1) /* 386 page roundup */
/* Header record of BSD UNIX executable file */
struct exec exec;
long far_read(), to_long();
char far *to_far();
char far *add_to_far(char far *p, long n);
/* Get a file we can open, attempt to load it */
main(argc, argv)
char *argv[];
{ int fd, i;
long addr, totalsz;
char far *base;
if (argc != 2) {
printf("usage: boot <filename>\n");
exit(1);
}
fd = open(argv[1], O_BINARY);
if (fd < 0) {
printf("boot: Cannot open file \"%s\" \n", argv[1]);
exit(1);
}
/* Reasonable file to load? */
i = read(fd, (char *)&exec, sizeof exec);
if (i != sizeof exec ||
(exec.a_magic != OMAGIC && exec.a_magic != NMAGIC
&& exec.a_magic != ZMAGIC)) {
printf("Not a recognized object file format\n");
exit(1);
}
/* Allocate buffer for temporary copy of protected mode executable
Buffer space requirements: |<--a.out------------>| pageroundup heap */
totalsz = exec.a_text + exec.a_data + exec.a_bss + 4096L + 20*1024L;
/* Pad with trailing portion to put protected mode entry code in */
base = farmalloc(totalsz + 64*1024L);
if (base == 0) {
printf("Cannot allocate enough memory\n");
exit(1);
}
/* Load Instruction (e.g. text) portion of file */
printf("Text %ld", exec.a_text);
if (far_read(fd, base, exec.a_text) != exec.a_text)
goto eof;
/* Load Data portion of file */
addr = exec.a_text;
/* Adjust for page alignment for pure procedure format */
if (exec.a_magic == NMAGIC && (addr & (PGSIZE-1)))
while (addr & CLOFSET)
* add_to_far(base, addr++) = 0;
printf("\nData %ld", exec.a_data);
if (far_read(fd, add_to_far(base,addr), exec.a_data) != exec.a_data)
goto eof;
/* Clear Uninitialized data (BSS) space */
addr += exec.a_data;
printf("\nBss %ld", exec.a_bss);
for ( ; addr < totalsz; )
* add_to_far(base,addr++) = 0;
if(exec.a_entry)
printf("\nStart 0x%lx", exec.a_entry);
#ifdef CKSUM
/* Optionally calculate checksum to validate against cross host's copy. */
far_cksum(base, addr-1L);
#endif CKSUM
printf("\n");
/* Effect copydown to absolute 0 and entry into protected mode at
location "a_entry". */
transfer(base, totalsz, exec.a_entry);
/* NOTREACHED */
eof:
printf(" - File incomplete, load aborted\n");
exit(1);
}
/* We use the routines below to always keep far pointers normalized
* to simplify comparision/subtraction. */
char far *to_far(l) long l; {
unsigned seg, offs;
seg = l>>4;
offs = l & 0xf;
return(MK_FP(seg,offs));
}
long to_long(f) char far *f; {
unsigned long l;
l = FP_SEG(f)*16L + (unsigned long)FP_OFF(f);
return(l);
}
char far *add_to_far(f,l) char far *f; long l; {
return(to_far(to_long(f)+l));
}
char far *normalize(f) char far *f; {
unsigned seg,offs ;
/* add in offset */
seg = FP_SEG(f); offs = FP_OFF(f);
seg += (offs >> 4) ; offs &= 0xf ;
return(MK_FP (seg, offs));
}
/* read() that works anywhere in DOS address space for any size data,
* works via bounce buffer. Not designed for speed or elegance. */
long far_read(io, base, len) int io; long len; char far *base; {
char far *fp;
/* normalize far pointer to handle segment rollover case */
fp = base = normalize(base);
while (len) {
static char dbuf[PGSIZE];
long rlen,tlen;
/* bounce buffer between my data segment and ultimate dest */
tlen = (len > PGSIZE)? PGSIZE : len;
if ((rlen = read (io, dbuf, tlen)) < 0) return (rlen);
/* shoot into place */
movedata (_DS, (unsigned)dbuf, FP_SEG(fp), FP_OFF(fp), rlen);
/* update transfer address and count */
fp = add_to_far(fp, rlen);
len -= rlen ;
if (tlen != rlen) break ;
}
return (to_long(fp) - to_long(base));
}
extern far protentry(); /* known to be less than 0x200 bytes long */
extern far gatea20();
/* set up to transfer to 386 program; call protentry to do the dirty work. */
transfer(base, len, entry) char far *base; long len, entry; {
unsigned seg,offs ;
long rbase;
char far *fp;
/* Copy code to top of the system and execute there. This keeps it
from getting stepped on. */
/* make 32 bit address */
rbase = to_long(base);
fp = add_to_far(base,len);
seg = FP_SEG(fp); offs = FP_OFF(fp);
/* protect possible conflict of top paragraph of bss */
if (offs) seg++ ;
/* force to protentry's offset so offsets agree */
offs = FP_OFF(&protentry);
movedata (FP_SEG(&protentry), offs, seg, offs, PGSIZE);
/* degate A20 - from now on, full physical memory address bus */
gatea20();
/* enter prot_entry program, relocated to top of loaded program, via
intersegment return */
asm push word ptr rbase+2 ;
asm push word ptr rbase ;
asm push word ptr len+2 ;
asm push word ptr len ;
asm push word ptr entry+2 ;
asm push word ptr entry ;
asm push word ptr seg;
asm push word ptr offs;
asm db 0cbh; /* lret - intersegment return */
/* within protentry: go into 32 bit mode, copy entire system to 0 with
single string instruction, intrasegment jump to entry point */
printf("protentry returned?!?\n");
exit(1);
/* NOTREACHED */
}
#ifdef CKSUM
/* 16 bit checksum of program. */
far_cksum(base, len) long len; char far *base; {
char far *tmp;
unsigned seg,offs ;
long nbytes,sum, tlen;
tmp = base;
sum = 0;
nbytes = 0;
while (len) {
/* normalize far pointer to handle segment rollover case */
tmp = normalize(tmp);
/* Do a page at a time */
tlen = (len > PGSIZE)? PGSIZE : len;
len -= tlen ;
while (tlen--) {
nbytes++;
if (sum&01)
sum = (sum>>1) + 0x8000;
else
sum >>= 1;
sum += *tmp++ ;
sum &= 0xFFFF;
}
}
printf("\nChecksum %05lu%6ld ", sum, (nbytes+CLSIZE)/PGSIZE);
}
#endif CKSUM
[LISTING TWO]
/* Excerpted with permission from 4.3BSD include file
* "/usr/include/sys/exec.h"
* Redistribution and use in source and binary forms are freely permitted
* provided that the above copyright notice and attribution and date of work
* and this paragraph are duplicated in all such forms.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* Header prepended to each a.out file.
*/
struct exec {
long a_magic; /* magic number */
unsigned long a_text; /* size of text segment */
unsigned long a_data; /* size of initialized data */
unsigned long a_bss; /* size of uninitialized data */
unsigned long a_syms; /* size of symbol table */
unsigned long a_entry; /* entry point */
unsigned long a_trsize; /* size of text relocation */
unsigned long a_drsize; /* size of data relocation */
};
#define OMAGIC 0407 /* old impure format */
#define NMAGIC 0410 /* read-only text */
#define ZMAGIC 0413 /* demand load format */
[LISTING THREE]
title _gatea20
; Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
; Written by William Jolitz, July 1989
; THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
; IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
; WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
; (void) gatea20();
; Enable Address Bit 20 that was disabled by BIOS for MSDOS
; We need it off to use entire memory space of the AT.
; We do this just prior to entering protected mode, never to return.
;
_TEXT segment byte public 'CODE'
assume cs:_TEXT,ds:_TEXT
_TEXT ends
Status_Port equ 64h ; 8042 Status Port
Cmd_rdy equ 2 ; Keyboard is ready?
Write_outpt equ 0d1h ; Write next data to output port
Port_A equ 60h ; 8042 Keyboard Scan and Diagnostic
EnableA20 equ 0dfh ; Enable Address bit 20 for use
_TEXT segment byte public 'CODE'
; Wait for Keyboard controller to be ready for command
wait42 proc near
chkrdy:
in al, Status_Port
and al, Cmd_rdy
jnz chkrdy
ret
wait42 endp
; Turn on A20 again.
_gatea20 proc far
call wait42
mov al, Write_outpt
out Status_Port, al
call wait42
mov al, EnableA20
out Port_A, al
call wait42
ret
_gatea20 endp
public _gatea20
_TEXT ends
end
[LISTING FOUR]
title protentry
; Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
; Written by William Jolitz 7/89
; Redistribution and use in source and binary forms are freely permitted
; provided that the above copyright notice and attribution and date of work
; and this paragraph are duplicated in all such forms.
; THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
; IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
; WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
; protentry(entry,len,addr,...) long entry,len,addr;
; Entered via jump or "ret" (e.g. no return address on stack),
; builds necessary data structures and transfers into 32-bit
; mode, then copies the 32-bit mode program at address "addr"
; and byte length "len" to location 0 and enters the program
; at location "entry". Note that both "entry" and "addr" are
; true 32-bit absolute pointers, NOT segment:offset pairs. It
; is assumed that both the stack and this program will not be
; overwritten in the subsequent copy to 0 of the program to be
; entered, so caller is responsible to place this in a location
; above the program.
;
; Note that this program is position-independant (self relocating).
;
; Any additional args past the necessary three will be passed on the
; stack to the entered program [note: we obviously don't provide a
; "return" address]
;
_TEXT segment byte public 'CODE'
assume cs:_TEXT,ds:nothing
_TEXT ends
Data32 equ 66h ; prefix to toggle 16/32 data operand
JMPFAR equ 0eah ; opcode for JMP intersegment
.186 ; allow use of shl ax,cnt insn
_TEXT segment byte public 'CODE'
_protentry proc far
jmp short relstrt
; Global Descriptor Table contains three descriptors:
; 0h: Null: not used
; 8h: Code: code segment starts at 0 and extents for 4 gbytes
; 10h: Data: data segment starts at 0 and extends for 4 gbytes(overlays code)
GDT:
NullDesc dw 0,0,0,0 ; null descriptor - not used
CodeDesc dw 0FFFFh ; limit at maximum: (bits 15:0)
db 0,0,0 ; base at 0: (bits 23:0)
db 10011111b ; present/priv level 0/code/conforming/readable
db 11001111b ; page granular/default 32-bit/limit(bits 19:16)
db 0 ; base at 0: (bits 31:24)
DataDesc dw 0FFFFh ; limit at maximum: (bits 15:0)
db 0,0,0 ; base at 0: (bits 23:0)
db 10010011b ; present/priv level 0/data/expand-up/writeable
db 11001111b ; page granular/default 32-bit/limit(bits 19:16)
db 0 ; base at 0: (bits 31:24)
; Load Pointers for Tables
; contains 6-byte pointer information for: LIDT, LGDT
; Interrupt Descriptor Table pointer
IDTPtr dw 7FFh ; limit at maximum (allows all 256 interrupts)
dw 0 ; base at 0: (bits 15:0)
dw 0 ; base at 0: (bits 31:16)
; Global Descriptor Table pointer
GDTPtr dw 17h ; limit to three 8 byte selectors(null,code,data)
dw offset GDT ; base address of GDT (bits 15:0)
dw 0h ; base address of GDT (bits 31:16)
; Constructed instruction for entry into 32 bit protected mode
; ljmp far Note
dispat: db Data32 ; 32-bit override prefix
db JMPFAR ; opcode for JMP intersegment
offl dw 0 ; starting address of 32-bit code (low-word)
dw 0h ; starting address (high word of linear address)
dw 8h ; CodeDesc selector=8h
relstrt:
cli ; disable interrupts
; do address fixups
mov ax,ss ; first, make a new 32 bit stack pointer!
mov cx,4
shl ax,cl ; ax now contains segment address low 16 bits
mov bx,ss
mov cx,12
shr bx,cl ; bx now contains segment address high 16 bits
add ax,sp
adc bx,0 ; ax contains esp 15:0, bx contains esp 31:16
mov si,ax ; pass new stack to 32bit mode via si & di
mov di,bx
mov ax,cs
mov cx,4
shl ax,cl ; ax now contains segment address low 16 bits
mov bx,cs
mov cx,12
shr bx,cl ; bx now contains segment address high 16 bits
mov cx,cs:GDTPtr+2
mov dx,bx
add cx,ax
mov cs:GDTPtr+2,cx
adc cs:GDTPtr+4,dx
mov cx, OFFSET(cpydwn)
mov dx,bx
add cx,ax
mov cs:offl,cx ; overflow?
adc cs:offl+2,dx
; Load the descriptor tables
; lidt cs:IDTPtr ; load Interrupt Descriptor Table
db 2eh,0Fh,01h,00011110b
dw offset IDTPtr
; lgdt cs:GDTPtr ; load Global Descriptor Table
db 2Eh,0Fh,01h,00010110b
dw offset GDTPtr
; smsw ax ; put Machine Status Word in AX
db 0fh, 01h, 11100000b
or al,1 ; activate Protection Enable bit
; lmsw ax ; store Machine Status Word, begin protected mode
db 0fh,01h,11110000b
jmp short Next ; flush prefetch queue
; Load the segment registers with approriate descriptor selectors
Next: mov bx,10h ; set segment registers to DataDesc
mov ss,bx ; load SS,DS,ES segment registers with DataDesc
mov ds,bx
mov es,bx
; Load CS via above's constructed ljmp, entering 32 bit protected mode
jmp short dispat
; Finally running in Protected 32-bit Mode
cpydwn:
mov ax,di ; movl %edi,%eax
shl ax,16 ;db 0c1h,0e0h,10h ; shll $16,%eax
db Data32
mov ax,si ; movw %si,%ax
mov sp,ax ; movl %eax,%esp
pop ax ; pop eax ; entry addr
pop cx ; pop ecx ; byte size
pop si ; pop esi ; source address
xor di,di ; xor edi,edi ; destination address
cld
rep movsb ; copy into place
mov sp,si ; movl esp,esi
jmp ax ; jmp eax ; go to entry
_protentry endp
public _protentry
_TEXT ends
end
[LISTING FIVE]
/* Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
* Written by William Jolitz 7/89
* Redistribution and use in source and binary forms are freely permitted
* provided that the above copyright notice and attribution and date of work
* and this paragraph are duplicated in all such forms.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* This program copies a BSD filesystem out of an MSDOS file and
* places it on an pre-reserved disk partition. Note that both the
* geometry of the particular disk, and the particulars of the
* BSD partition need to be adjusted to suit the drive on which this will
* be used. Normally, this would be a very rude requirement, but
* we tolerate this because this program is a throw-away used to get
* us started, and we have better schemes to deal with configuration
* a little further down the pike.
* Currently works with TURBO C 1.5 .
*/
#include <bios.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include "diskl.h"
/* Disk geometry (here, a NEC DS5146). Adjust parameters to suit drive. */
#define NCYL 615
#define NTRACK 8
#define NSECT 17
#define BSIZE 512 /* Disk block size */
/* Location & size of root partition. Adjust for drive partition layout. */
#define OFF_CYL 290 /* Cylinder offset of start of BSD root partition */
#define ROOTSZ 50 /* size of root partition, in units of cylinders */
char trkbuf[NSECT*BSIZE];
struct label_blk {
char bufr[LABELOFFSET];
struct disklabel dl;
} lbl;
main (argc, argv) char *argv[]; {
int fi, rem, cyl, head, sector, tfrcnt;
if (argc != 2) {
printf ("usage: cpfs <rootfs>\n");
exit (1);
}
fi = open (argv[1],O_BINARY);
if (fi < 0) {
printf ("Cannot open \"%s\" file to read filesystem\n",
argv[1]);
exit (1);
}
cyl = OFF_CYL;
tfrcnt = head = 0;
#ifndef FIRST
/* check for presence of disklabel */
biosdisk (2, 0x80, 0, OFF_CYL, LABELSECTOR, 1, &lbl);
if (lbl.dl.dk_magic != DISKMAGIC) {
printf ("BSD Disk partition does not have a label!\n");
exit (1);
}
/* Treat first track of data special; use disk label in first block of
* file to validate that the file to be loaded and disk drive
* partition are appropriate for each other. */
read (fi, trkbuf, BSIZE);
if (strncmp (trkbuf, &lbl, BSIZE) != 0) {
printf ("BSD root partition and filesystem mismatch!\n");
exit (1);
}
/* reset filesystem file to beginning */
lseek (fi, 0, SEEK_SET);
#endif
printf ("WARNING! About to overwrite disk (will loose previous\n");
printf ("contents). Are you certain of your use of this program?");
if (getche () != 'y') exit (1);
printf("\n");
/* Transfer file to absolute disk section, a track at a time,
because we're impatient. */
while ((rem = read (fi, trkbuf, NSECT*BSIZE)) == NSECT*BSIZE) {
biosdisk (3, 0x80, head, cyl, 1, NSECT, trkbuf);
if (++head == NTRACK) {
head = 0;
if (++cyl > NCYL || cyl > OFF_CYL+ROOTSZ ) {
printf ("Overran root partition!\n");
exit (1);
}
}
tfrcnt += NSECT;
printf ("Amount transferred %5dK bytes\r",
tfrcnt*BSIZE/1024);
}
/* Transfer any remainder leftover in track buffer. */
if (rem > BSIZE-1) {
biosdisk (3, 0x80, head, cyl, 1, rem/BSIZE, trkbuf);
tfrcnt += rem/BSIZE;
printf ("Amount transferred %5dK bytes\n",
tfrcnt*BSIZE/1024);
}
exit (0);
}
[LISTING SIX]
/* Copyright (c) 1985,1986,1989,1990 Micheal J. Karels. All rights reserved.
* Based on a concept by Sam Leffler. Written by Michael J. Karels 4/85
* Revised by William Jolitz 86-90.
* Redistribution and use in source and binary forms are freely permitted
* provided that the above copyright notice and attribution and date of work
* and this paragraph are duplicated in all such forms.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* Each disk has a label which includes information about the hardware
* disk geometry, filesystem partitions, and drive specific information.
* The label is in block 1, offset from the beginning to leave room
* for a bootstrap, etc.
*/
#define LABELSECTOR 1 /* sector containing label */
#define LABELOFFSET (BSIZE-120) /* offset of label in sector */
#define DISKMAGIC 0xabc /* The disk magic number */
#define DTYPE_ST506 1 /* ST506 Winchester */
#define DTYPE_FLOPPY 2 /* 5-1/4" minifloppy */
#define DTYPE_SCSI 3 /* SCSI Direct Access Device */
struct disklabel {
short dk_magic; /* the magic number */
short dk_type; /* drive type */
struct dcon {
short dc_secsize; /* # of bytes per sector */
short dc_nsectors; /* # of sectors per track */
short dc_ntracks; /* # of tracks per cylinder */
short dc_ncylinders; /* # of cylinders per unit */
long dc_secpercyl; /* # of sectors per cylinder */
long dc_secperunit; /* # of sectors per unit */
long dc_drivedata[4]; /* drive-type specific information */
} dc;
struct dpart { /* the partition table */
long nblocks; /* number of sectors in partition */
long cyloff; /* starting cylinder for partition */
} dk_partition[8];
char dk_name[16]; /* pack identifier */
};
#define dk_secsize dc.dc_secsize
#define dk_nsectors dc.dc_nsectors
#define dk_ntracks dc.dc_ntracks
#define dk_ncylinders dc.dc_ncylinders
#define dk_secpercyl dc.dc_secpercyl
#define dk_secperunit dc.dc_secperunit
/* Drive data for ST506. */
#define dk_precompcyl dc.dc_drivedata[0]
#define dk_ecc dc.dc_drivedata[1] /* used only when formatting */
#define dk_gap3 dc.dc_drivedata[2] /* used only when formatting */
/* Drive data for SCSI */
#define dk_blind dc.dc_drivedata[0] /* can we work in "blind" i/o */
[LISTING SEVEN]
/* Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
* Written by William Jolitz 7/89
* Redistribution and use in source and binary forms are freely permitted
* provided that the above copyright notice and attribution and date of work
* and this paragraph are duplicated in all such forms.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* This program copies a MSDOS file to BSD's idea of a swap partition,
* known to be the second one in the disklabel. Typical use is to place
* a TAR formatted file, obtained from a cross-host, onto swap. Then
* BSD is booted with the boot program and the BSD tar utility is
* used to extract the files being transferred within the TAR image,
* hopefully before we need to page on the swap space. Again, this
* program is rude in requiring one to adjust the manifest constant
* denoting the cylinder on which the BSD root filesystem appears,
* but this is another throw-away program to get the real work started.
* Currently works with TURBO C 1.5 .
*/
#include <bios.h>
#include <alloc.h>
#include <fcntl.h>
#include <sys\stat.h>
#include "diskl.h"
/* Location of root partition. Adjust to suit given drive partition layout. */
#define OFF_CYL 290 /* Cylinder offset of start of BSD root partition */
char *trkbuf;
#define BSIZE 512
struct label_blk {
char bufr[LABELOFFSET];
struct disklabel dl;
} lbl;
main(argc, argv) char *argv[]; {
int fi, rem, cyl, head, tfrcnt;
int bsize, ncyl, ntrack, nsect, off_cyl, maxcyl;
if (argc != 2) {
printf("usage: cpsw <file>\n");
exit(1);
}
fi = open(argv[1], O_BINARY);
if (fi < 0) {
printf("Cannot open \"%s\" file to BSD swap\n",
argv[1]);
exit(1);
}
/* check for presence of disklabel */
biosdisk(2, 0x80, 0, OFF_CYL, LABELSECTOR, 1, &lbl);
if (lbl.dl.dk_magic != 0xabc) {
printf("BSD root disk partition does not have a label!\n");
exit(1);
}
/* Extract disk geometry and swap partition location from disk label. */
bsize = lbl.dl.dk_secsize;
nsect = lbl.dl.dk_nsectors;
ntrack = lbl.dl.dk_ntracks;
off_cyl = lbl.dl.dk_partition[1].cyloff;
maxcyl = lbl.dl.dk_partition[1].cyloff +
lbl.dl.dk_partition[1].nblocks / lbl.dl.dk_secpercyl;
/* Allocate track buffer */
trkbuf = malloc (nsect*bsize);
printf("WARNING! About to overwrite disk (will loose previous\n");
printf("contents). Are you certain of your use of this program?");
if (getche() != 'y') exit(1);
printf("\n");
tfrcnt = head = 0;
cyl = off_cyl;
/* Transfer file to absolute disk section, a track at a time,
because we're impatient. */
while ((rem = read(fi, trkbuf, nsect*bsize)) == nsect*bsize) {
biosdisk(3, 0x80, head, cyl, 1, nsect, trkbuf);
if (++head == ntrack) {
head = 0;
if (++cyl > maxcyl) {
printf("Overran swap partition!\n");
exit(1);
}
}
tfrcnt += nsect;
printf("Amount transferred %5dK bytes\r",
tfrcnt*BSIZE/1024);
}
/* Transfer any remainder leftover */
if (rem > BSIZE-1) {
biosdisk(3, 0x80, head, cyl, 1, rem/bsize, trkbuf);
tfrcnt += rem/bsize;
printf("Amount transferred %5dK bytes\n",
tfrcnt*bsize/1024);
}
exit(0);
}